/****************************************************************************************
*            . .. .                                                                     *
*                    ...                                                                *
*                       .":                                                             *
*   .                      u                                                            *
* ..     .:uxkkOkkx=.      "k'                                                          *
*.     "k00O0ko==uk00x'     OO.                       IBE-CAE                           *
*'   .xK0O00: 'xx" x0Ku    .O0:     Copyright (C) by Internet Based Engineering         *
*   .O0OO00= oKOk:"O0O'    :00=                 All rights reserved.                    *
*.  =0OOO00" =OOO0Oo'     =0OO:                      www.ibe.cn                         *
*.  u0OOOO0O'          .o00OOO.                                                         *
* . :KOOOOO00xu=:::=uok00OOOO"                                                          *
*   .x00OOOOOO0000000OOOOOOx.                                                           *
*    .u00OOOOOOOOOOOOOOOOO=                                                             *
*      .ukOOOOOOOOOOOOku'                                                               *
*          .'::==::'.                                                                   *
****************************************************************************************/

#ifndef IBE_FIELD_INFORMATION_H_
#define IBE_FIELD_INFORMATION_H_

#include <string>
#include <vector>

#include "IBE_Object.h"

namespace ibe_common
{
    /**
    * @class IBE_FieldData
    * @brief 场数据信息
    * @author liupeng
    */
    class IBE_COMMON_EXPORT IBE_FieldData : public IBE_Object
    {
    public:
        explicit IBE_FieldData();
        IBE_FieldData( IBE_FieldData* fieldInfo );
        ~IBE_FieldData();

        IBE_TypeMacro( ibe_common, IBE_FieldData, ibe_common, IBE_Object );

        //! 场类型
        enum IBE_FieldType
        {
            IBE_FIELD_TYPE_SCALAR,  //!< 标量，分量数为1
            IBE_FIELD_TYPE_VECTOR,  //!< 矢量，分量数为3
            IBE_FIELD_TYPE_TENSOR   //!< 张量，分量数大于等于6
        };

        //! 场位置
        enum IBE_FieldLocationType
        {
            IBE_FIELD_LOCATION_NODE,                //!< 节点场
            IBE_FIELD_LOCATION_CELL_CENTER,         //!< 单元场
            IBE_FIELD_LOCATION_CELL_INTEGRATION,    //!< 单元积分点场
            IBE_FIELD_LOCATION_CELL_NODE            //!< 单元节点场
        };

        //@{
        /**
        * @brief 设置/获取场数据名称
        *
        * @param name 场数据名称
        * @return 场数据名称
        */
        virtual void SetFieldDataName( const char* name );
        virtual const char* GetFieldDataName()
        {
            return this->fieldDataName_.c_str();
        }
        //@}

        /**
         * @brief 设置/获取场单位
         *
         * @param u 场单位字符串
         * @return 场单位
         */
        virtual void SetUnit( const char* u );
        virtual const char* GetUnit()
        {
            return this->unit_.c_str();
        }

        /**
         * @brief 设置/获取场分量的名称
         *
         * @param paramName 场分量的名称，以“:”分隔，如矢量场为“x:y:z”，对称张量场为“xx:yy:zz:xy:yz:zx”
         * @return 场分量的名称
         */
        virtual void SetSubNames( const char* subNames );
        virtual const char* GetSubNames();

        /**
         * @brief 设置/获取数据是否是原始数据，默认是false
         *
         * @param isOri 是否是原始数据
         * @return 是否是原始数据
         */
        virtual void SetIsOriginal( bool isOri );
        virtual bool IsOriginal()
        {
            return this->isOriginal_;
        }

        //@{
        /**
         * @brief 设置场数据
         *
         * @param type 场类型，IBE_FieldData::IBE_FieldType枚举值
         * @param numOfComponent 分量数
         * @param loc 场位置，IBE_FieldData::IBE_FieldLocationType枚举值
         * @param num 节点场时为节点数，单元场时为单元数
         * @param newData 场数据，长度为：（每个newLength值*分量数）的累加
         * @param newLength 存储每个单元里的数据数量，长度为单元个数。data的长度为：每个（该数量*分量数）的累加。
         * 只有单元积分点场（Cell Integration）和表示单元节点场（Cell Node）时才有
         */
        virtual void SetData( const int type, const int numOfComponent, const int loc, const int64_t num, float* newData,
                              uint8_t* newLengths = nullptr );
        /**
         * @brief 设置场数据
         *
         * @param type 场类型，，IBE_FieldData::IBE_FieldType枚举值
         * @param numOfComponent 分量数
         * @param loc 场位置，IBE_FieldData::IBE_FieldLocationType枚举值
         * @param num 节点场时为节点数，单元场时为单元数
         * @param newDataSize 场数据数组长度
         * @param newData 场数据，单元积分点场时，存储方式为：单元1（积分点1（分量1、分量2 ...）、积分点2（分量1、分量2 ...） ...）、单元2 ...
         * @param newCompRange 场数据每个分量的最大值和最小值范围，数据长度为分量的2倍
         * @param newMagnRange 模长范围，即场数据根号平方和的最大值和最小值范围
         * @param newLength 存储每个单元里的数据数量，长度为单元个数。
         * 只有单元积分点场（Cell Integration）和表示单元节点场（Cell Node）时才有
         * @param newOffset 存储每个单元数据在data中的起始索引号（通过lengths和分量数相乘计算得到对应的位置），长度为单元个数。
         * 只有单元积分场（Cell Integration）和表示单元节点场（Cell Node）时才有
         */
        virtual void SetData( const int type, const int numOfComponent, const int loc, const int64_t num, const int64_t newDataSize,
                              float* newData, double* newCompRange, double* newMagnRange,
                              uint8_t* newLengths = nullptr, int64_t* newOffset = nullptr );
        virtual int GetFieldType()
        {
            return this->fieldType_;
        }
        virtual int GetFieldLocation()
        {
            return this->fieldLocation_;
        }
        virtual int64_t GetDataSize()
        {
            return this->dataSize_;
        }
        virtual float* GetData()
        {
            return this->data_;
        }
        virtual uint8_t* GetLengths()
        {
            return this->lengths_;
        }
        virtual int64_t* GetOffset()
        {
            return this->offset_;
        }
        virtual double* GetComponentRange()
        {
            return this->compRange_;
        }
        virtual double* GetMagnRange()
        {
            return this->magnRange_;
        }
        virtual int GetNumberOfComponent()
        {
            //return this->GetNumberOfComponentByFieldType( this->fieldType );
            return this->numberOfComponents_;
        }
        virtual int64_t GetNumberOfPointCell()
        {
            return this->numberOfPointCell_;
        }
        virtual int64_t GetLengthsSize()
        {
            if( this->lengths_ )
            {
                return this->numberOfPointCell_;
            }
            return 0;
        }
        virtual int64_t GetOffsetSize()
        {
            if( this->offset_ )
            {
                return this->numberOfPointCell_;
            }
            return 0;
        }
        //@}

        /**
         * @brief 获取场类型对应的分量数
         *
         * @param type 场类型，，IBE_FieldData::IBE_FieldType枚举值
         * @return 分量数
         */
        virtual int GetNumberOfComponentByFieldType( const int type );

        virtual void SetUserInfor( const char* info );
        virtual const char* GetUserInfor()
        {
            return this->userInfor_.c_str();
        }

        virtual void Initialize() override;
        virtual void InitData();
        /**
         * @brief 释放数据
         */
        virtual void ClearData();

        /**
         * @brief 数据类型（VTK_INT、VTK_TYPE_UINT8等），默认为VTK_INT（6），暂时没有用
         */
        virtual void SetDataType( const int type );
        virtual int GetDataType()
        {
            return this->dataType_;
        }

        virtual void Copy( ibe_common::IBE_Object* obj ) override;

    protected:
        std::string fieldDataName_; //!< 场数据名称

        double* compRange_; //!< 场数据每个分量的最大值和最小值范围，数据长度为分量的2倍，标量长度为2，矢量长度为6，张量长度为12
        double magnRange_[2]; //!< 模长范围，即场数据根号平方和的最大值和最小值范围
        int fieldType_; //!< 场类型，IBE_FieldData::IBE_FieldType枚举值
        int fieldLocation_; //!< 场位置，IBE_FieldData::IBE_FieldLocationType枚举值
        bool isOriginal_; //!< 是否是原始数据，用于判断是否计算结果的原始数据
        std::string unit_;  //!< 场单位
        int numberOfComponents_; //!< 分量数，默认为1
        std::string subCompNames_; //!< 场分量的名称，以“:”分隔，如矢量场为“x:y:z”，对称张量场为“xx:yy:zz:xy:yz:zx”
        int64_t numberOfPointCell_; //!< 节点场时为节点数，单元场时为单元数
        int64_t dataSize_; //!< 场数据数据长度
        float* data_; //!< 场数据
        uint8_t* lengths_; //!< 存储每个单元里的数据数量，长度为单元个数。data的长度为：每个（该数量*分量数）的累加。
                          //!< 只有单元积分场（Cell Integration）和表示单元节点场（Cell Node）时才有
        int64_t* offset_; //!< 存储每个单元数据在data中的起始索引号（通过lengths和分量数相乘计算得到对应的位置），长度为单元个数。
                         //!< 只有单元积分场（Cell Integration）和表示单元节点场（Cell Node）时才有
        std::string userInfor_; //!< 计算新的场数据时，存储一些标记信息

        int dataType_; //!< 数据类型（VTK_INT、VTK_TYPE_UINT8等），暂时没有用
    private:
        IBE_FieldData( const IBE_FieldData& ) = delete;
        IBE_FieldData& operator=( const IBE_FieldData& ) = delete;
    };
} // namespace ibe_common

#endif // IBE_FIELD_INFORMATION_H_